#include "Texture.h"

#include "QHutu.h"

#include <map>

#include <QJsonArray>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonDocument>

using namespace Softwarer;

namespace Horse
{
	void FileTexture::useTexture(int unit)
	{
		m_texture->bind(unit);
	}
	ITexture* createTextureFromFile(const QString& filepath)
	{
		QString text = QHutu::readTextFile(QHutu::applicationDirPath(filepath));
		QJsonDocument document = QJsonDocument::fromJson(text.toLocal8Bit());
		if (document.isObject() == false)
		{
			return nullptr;
		}
		QJsonObject rootObject = document.object();
		if (rootObject.contains("Src") == false || rootObject.contains("Type") == false)
		{
			return nullptr;
		}
		FileTexture* fileTexture = new FileTexture();
		QOpenGLTexture* texture = createQOpenGLTexture(rootObject.value("Type").toString());		
		QJsonValue srcValue = rootObject.value("Src");
		texture->setData(QImage(QHutu::applicationDirPath(srcValue.toString())).mirrored());
		if (rootObject.contains("WrapMode"))
		{
			texture = setWrapMode(texture, rootObject.value("WrapMode").toString());
		}
		texture = setFilter(texture, rootObject);
		fileTexture->setQOpenGLTexture(texture);
		return fileTexture;
	}
	QOpenGLTexture* setWrapMode(QOpenGLTexture* texture, const QString& wrapMode)
	{
		static std::map<QString, QOpenGLTexture::WrapMode> wrapModeMap = {
			{ "Repeat", QOpenGLTexture::Repeat },
			{ "MirroredRepeat", QOpenGLTexture::MirroredRepeat },
			{ "ClampToEdge", QOpenGLTexture::ClampToEdge },
			{ "ClampToBorder", QOpenGLTexture::ClampToBorder }
		};
		if (wrapModeMap.find(wrapMode) != wrapModeMap.cend()) {
			texture->setWrapMode(wrapModeMap.at(wrapMode));
		}
		return texture;
	}
	QOpenGLTexture* setFilter(QOpenGLTexture* texture, const QJsonObject& rootObject)
	{
		static std::map<QString, QOpenGLTexture::Filter> filterMap = {
			{ "Nearest", QOpenGLTexture::Nearest },
			{ "Linear", QOpenGLTexture::Linear },
			{ "NearestMipMapNearest", QOpenGLTexture::NearestMipMapNearest },
			{ "NearestMipMapLinear", QOpenGLTexture::NearestMipMapLinear },
			{ "LinearMipMapNearest", QOpenGLTexture::LinearMipMapNearest },
			{ "LinearMipMapLinear", QOpenGLTexture::LinearMipMapLinear }
		};
		if (rootObject.contains("MagnificationFilter"))
		{
			QString magnificationFilter = rootObject.value("MagnificationFilter").toString();
			if (filterMap.find(magnificationFilter) != filterMap.cend())
			{
				texture->setMagnificationFilter(filterMap.at(magnificationFilter));
			}
		}
		if (rootObject.contains("MinificationFilter"))
		{
			QString minificationFilter = rootObject.value("MinificationFilter").toString();
			if (filterMap.find(minificationFilter) != filterMap.cend())
			{
				texture->setMinificationFilter(filterMap.at(minificationFilter));
			}
		}
		return texture;
	}
	QOpenGLTexture* createQOpenGLTexture(const QString& target)
	{
		static std::map<QString, QOpenGLTexture::Target> targetMap = {
			{ "Target2D", QOpenGLTexture::Target2D }
		};
		QOpenGLTexture::Target textureTarget = QOpenGLTexture::Target2D;
		if (targetMap.find(target) != targetMap.cend()) {
			textureTarget = targetMap.at(target);
		}
		return new QOpenGLTexture(textureTarget);
	}
}